/*
 *   Copyright 2021 zzh
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 *
 */

package com.aduib.boot.common.event;

import com.aduib.boot.common.disruptor.Disruptors;
import com.aduib.boot.common.disruptor.ElementEventHandler;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.function.Predicate;

/**
 * @description: DisruptorEventMultiCaster
 * @author: zzh
 * @date: 2021/9/17 13:26
 */
@SuppressWarnings("all")
public class DisruptorEventMultiCaster implements EventMultiCaster {

  private Disruptors disruptor;

  private List<ElementEventHandler<?>> eventHandlers;

  public DisruptorEventMultiCaster() {}

  public DisruptorEventMultiCaster(List<ElementEventHandler<?>> eventHandlers) {
    this.eventHandlers = eventHandlers;
    createDisruptor();
  }

  public DisruptorEventMultiCaster(Disruptors disruptor) {
    createEventHandlers();
    this.disruptor = disruptor;
  }

  public DisruptorEventMultiCaster(
      Disruptors disruptor, List<ElementEventHandler<?>> eventHandlers) {
    this.disruptor = disruptor;
    this.eventHandlers = eventHandlers;
  }

  public static DisruptorEventMultiCaster create(ElementEventHandler<?>... handler) {
    DisruptorEventMultiCaster disruptorEventMultiCaster = new DisruptorEventMultiCaster();
    disruptorEventMultiCaster.createEventHandlers();
    for (ElementEventHandler<?> elementEventHandler : handler) {
      disruptorEventMultiCaster.addEventHandler(elementEventHandler);
    }
    disruptorEventMultiCaster.createDisruptor();
    return disruptorEventMultiCaster;
  }

  public <T> void createDisruptor() {
    if (Objects.isNull(disruptor)) {
      disruptor = Disruptors.<T>builder().addDefaultEventHandlers(eventHandlers).createAllOne();
    }
  }

  public void createEventHandlers() {
    if (Objects.isNull(eventHandlers)) {
      eventHandlers = new ArrayList<>();
    }
  }

  @Override
  public <T> EventMultiCaster addEventHandler(T eventListener) {
    eventHandlers.add((ElementEventHandler<?>) eventListener);
    return this;
  }

  @Override
  @SuppressWarnings("unchecked")
  public <T> EventMultiCaster addEventHandlers(List<T> eventListeners) {
    eventHandlers.addAll((Collection<? extends ElementEventHandler<?>>) eventListeners);
    return this;
  }

  @Override
  public EventMultiCaster removeEventHandler(Predicate predicate) {
    eventHandlers.removeIf(predicate);
    return this;
  }

  @Override
  public EventMultiCaster removeEventHandlers() {
    eventHandlers.clear();
    return this;
  }

  @Override
  @SuppressWarnings("unchecked")
  public <T> EventMultiCaster publishEvent(T event) {
    disruptor.publishEvent(event);
    return this;
  }
}
